

from LogNumber import LogNumber
from LogFile import LogFile
from MemTable import MemTable
from Schedule import Schedule
from SSTables import SSTables
#No recovery mode TODO:
class KvDB(object):
    def __init__(self, directory = "./tmpdb"):
        self.__directory = directory

        self.__logNumber = LogNumber()
        self.__logFile = LogFile(self.__directory, self.__logNumber.next())
        self.__memtable = MemTable()
        self.__ssts = SSTables(self.__directory)

        self.__schedule = self._startSchedule()


    def close(self):
        task = Schedule.newLevel0Task(self.__memtable, self.__logFile)
        self.__schedule.pushBack(task)

        self._stopSchedule(self.__schedule) #wait first

        self.__schedule = None
        self.__ssts = None
        self.__memtable = None
        self.__logFile = None

    def _stopSchedule(self, schedule):
        schedule.stop()
         
    def _startSchedule(self):
        schedule = Schedule()
        schedule.pushBack(Schedule.newCompactTask(self.__ssts))
        schedule.start()
        return schedule

    def _concate(self, key, val):
        return "%s:%s" % (key, val)

    def _makeRoomForWrite(self, needSpace):
        if not self.__logFile.hasFreeSpace(needSpace):
            task = Schedule.newLevel0Task(self.__memtable, self.__logFile)
            self.__schedule.pushBack(task)

            self.__memtable = MemTable()
            self.__logFile = LogFile(self.__directory, self.__logNumber.next())
        #end if

    def put(self, key, val):
        binary = self._concate(key, val)
        self._makeRoomForWrite(len(binary))

        self.__logFile.append(binary)
        return self.__memtable.put(key, val)

    def get(self, key):
        val = self.__memtable.get(key)
        if val is not None:
            return val
        #end if

        #TODO:
        """
        if self.__immutable is not None:
            val = self.__immutable.get(key)
            if val is not None:
                return val
            #endif
        """

        return self.__ssts.get(key) 

import unittest
class TestKvDb(unittest.TestCase):
    def test(self):
        db = KvDB("./chenglun")
        def put(db, key, value):
            ret = db.put(key, value)
            self.assertTrue(ret == 0)

        for i in range(1000):
            put(db, str(i), "hello"+str(i))

        ret = db.get("1")
        self.assertTrue(ret == "hello1")
        db.close()


if __name__ == "__main__":
    suite = unittest.TestSuite([
        unittest.TestLoader().loadTestsFromTestCase(TestKvDb), 
    ])
    unittest.TextTestRunner(verbosity=2).run(suite)
